﻿using AIVision.Model.MachineModels;
using AIVision.Model.EntityModels;
using AIVision.Model.UIModels;
using AIVision.PLC.LiWi;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AIVision.PLC.MachineModule
{
    public class FeiLiao
    {
        private IntPtr _handle;
        private PLCConfigDto plcConfig;
        private readonly FeiLiaoStatusModel feiLiaoStatus;
        private readonly MachineStatusModel machineStatus;
        private readonly IEventAggregator eventAggregator;
        public bool YuanDianXH
        {
            get
            {
                uint in10 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 10, ref in10);
                feiLiaoStatus.YuanDianXH = in10 == 1;
                return in10 == 1;
            }
        }
        public Task RunTask { get; set; } = new Task(() => { });
        public int Location
        {
            get
            {
                float dpos = 0;
                Shell.PMC_GetDpos(_handle, 3, ref dpos);
                int v;
                if (dpos == plcConfig.FeiLiaoRunPos1)
                    v = 1;
                else if (dpos == plcConfig.FeiLiaoRunPos2)
                    v = 2;
                else if (dpos == plcConfig.FeiLiaoRunPos3)
                    v = 3;
                else
                {
                    v = 0;
                }
                feiLiaoStatus.Location = v;
                return v;
            }
        }

        public bool ServoRunXH
        {
            get
            {
                int runFlag = -1;
                Shell.PMC_GetIfIdle(_handle, 3, ref runFlag);
                feiLiaoStatus.ServoRunXH = runFlag == 0;
                return runFlag == 0;
            }
        }
        public FeiLiao(FeiLiaoStatusModel feiLiaoStatus,MachineStatusModel machineStatus, IEventAggregator eventAggregator)
        {
            this.feiLiaoStatus = feiLiaoStatus;
            this.machineStatus = machineStatus;
            this.eventAggregator = eventAggregator;
        }
        public void Init(IntPtr _handle, PLCConfigDto plcConfig)
        {
            this._handle = _handle;
            this.plcConfig = plcConfig;
        }



        public void ResetLocationAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(ResetLocation,CTS.Token);
                RunTask.Start();
            }
        }
        public void ResetLocation()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                int ret0 = Shell.PMC_SetAtype(_handle, 3, 1); // 设置轴 0 轴类型为 1 
                ret0 += Shell.PMC_SetInvertStep(_handle, 3, 1);
                ret0 += Shell.PMC_SetUnits(_handle, 3, 1); // 设置轴 0 脉冲当量为 100 
                Shell.PMC_SetAxisEnable(_handle, 3, 0);
                ret0 += Shell.PMC_SetSpeed(_handle, 3, 500); // 设置轴 0 速度为 200units/s 
                if (!YuanDianXH)
                {
                    Shell.PMC_Single_Vmove(_handle, 3, -1);
                    timeout = 0;
                    while (!YuanDianXH)
                        WaitTimeout(10000);
                    Shell.PMC_Single_Cancel(_handle, 1, 3);
                }

                Shell.PMC_Single_Vmove(_handle, 3, 1);
                timeout = 0;
                while (YuanDianXH)
                    WaitTimeout(10000);
                Shell.PMC_Single_Cancel(_handle, 3, 3);

                ret0 = Shell.PMC_SetDpos(_handle, 3, 0); // 轴指令位置清 0 
                ret0 += Shell.PMC_SetMpos(_handle, 3, 0); // 编码器反馈位置清 0 
                ret0 += Shell.PMC_SetSpeed(_handle, 3, plcConfig.FeiLiaoRunSpeed); // 设置轴 0 速度为 200units/s 
                ret0 += Shell.PMC_SetAccel(_handle, 3, plcConfig.FeiLiaoRunSpeed * 10); // 设置轴 0 加速度为 2000units/s/s 
                ret0 += Shell.PMC_SetDecel(_handle, 3, plcConfig.FeiLiaoRunSpeed * 10); // 设置轴 0 减速度为 2000units/s/s 
                Shell.PMC_Single_MoveAbs(_handle, 3, plcConfig.FeiLiaoRunPos2);
            }
            catch (OperationCanceledException ex)
            {
                Shell.PMC_Single_Cancel(_handle, 3, 3);
            }
        }

        public void RunAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH && machineStatus.ResetLocationStatus)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(Run,CTS.Token);
                RunTask.Start();
            }
        }
        public void Run()
        {
            if (machineStatus.EmergencyStopXH && !machineStatus.ResetLocationStatus)
                return;
            try
            {
                Task.Delay(plcConfig.NGQuDelay).Wait();
                Shell.PMC_Single_MoveAbs(_handle, 3, plcConfig.FeiLiaoRunPos3);
                timeout = 0;
                while (ServoRunXH)
                    WaitTimeout(3000);
                Shell.PMC_SetOp(_handle, 3, 1);

                Shell.PMC_Single_MoveAbs(_handle, 3, plcConfig.FeiLiaoRunPos1);
                timeout = 0;
                while (ServoRunXH)
                    WaitTimeout(3000);
                Shell.PMC_SetOp(_handle, 3, 0);
                Task.Delay(300).Wait();
                Shell.PMC_Single_MoveAbs(_handle, 3, plcConfig.FeiLiaoRunPos2);
                timeout = 0;
                while (ServoRunXH)
                    WaitTimeout(3000);
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 3, 3);
            }
        }


        public void MonitorStatus()
        {
            float dpos = 0, mpos = 0, pfvalue = 0;
            Shell.PMC_GetDpos(_handle, 3, ref dpos);
            Shell.PMC_GetMpos(_handle, 3, ref mpos);
            Shell.PMC_GetMspeed(_handle, 3, ref pfvalue);
            feiLiaoStatus.DPos = dpos;
            feiLiaoStatus.MPos = mpos;
            feiLiaoStatus.Speed = pfvalue;

            var b = YuanDianXH;
            b = ServoRunXH;
            int i = Location;

        }


        #region WaitTimeout
        public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
        public delegate void TimeOutDelegate();
        private int timeout = 0;
        private void WaitTimeout(int waitTime, string msg = "", TimeOutDelegate timeOutDelegate = null)
        {
            // 检查是否请求取消
            CTS.Token.ThrowIfCancellationRequested();
            Task.Delay(1).Wait();
            timeout += 1;
            if (timeout > waitTime)
            {
                CTS.Cancel();
                if (timeOutDelegate != null)
                    timeOutDelegate();
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"等待超时:{msg}", "Red"));
            }
        }
        #endregion
    }
}
